/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 *  Copyright 2008 Global Sign In
 *  Copyright 2009 Fabrice Colin
 * 
 *  The MySQL FLOSS License Exception allows us to license this code under
 *  the LGPL even though MySQL is under the GPL.
 * 
 *  This code is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef _MYSQLBASE_H_
#define _MYSQLBASE_H_

#include <mysql/mysql.h>
#include <pthread.h>
#include <string>
#include <vector>

/// A row in a MySQL table.
class MySQLRow
{
	public:
		MySQLRow(MYSQL_ROW row, int nColumns);
		virtual ~MySQLRow();

		/// Returns the number of columns.
		int getColumnsCount(void) const;

		/// Returns the given column.
		std::string getColumn(int nColumn) const;

	protected:
		MYSQL_ROW m_row;
		int m_nColumns;

};

/// Results extracted from a MySQL table.
class MySQLResults
{
	public:
		MySQLResults(MYSQL_RES *results);
		virtual ~MySQLResults();

		/// Returns the number of rows.
		unsigned long getRowsCount(void);

		/// Returns whether there are more rows.
		bool hasMoreRows(void);

		/// Returns the name of the given column.
		std::string getColumnName(unsigned int nColumn);

		/// Returns the next row.
		MySQLRow *nextRow(void);

		/// Rewinds to the first row.
		bool rewind(void);

	protected:
		MYSQL_RES *m_results;
		my_ulonglong m_nRows;
		unsigned int m_nColumns;
		my_ulonglong m_nCurrentRow;

	private:
		MySQLResults(const MySQLResults &other);
		MySQLResults &operator=(const MySQLResults &other);

};

/// Simple C++ wrapper around the MySQL API.
class MySQLBase
{
	public:
		MySQLBase(const std::string &hostName,
			const std::string &databaseName,
			const std::string &userName,
			const std::string &password);
		virtual ~MySQLBase();

		/// Returns whether the database could be open.
		bool isOpen(void) const;

		/// Returns a new UUID.
		std::string getUniversalUniqueId(void);

		/// Escapes a string for use in a SQL statement.
		std::string escapeString(const std::string &text);

		/// Executes a SQL statement and doesn't return results.
		bool executeSimpleStatement(const std::string &sql,
			std::string &insertAutoId);

		/// Executes a SQL statement and returns results.
		MySQLResults *executeStatement(const char *sqlFormat, ...);

		/**
		  * Executes a SQL statement and returns results, with pagination.
		  * The statement shouldn't end with a semi-colon.
		  */
		MySQLResults *executeStatement(const std::string &sqlFormat,
			unsigned long min, unsigned long max);

	protected:
		pthread_mutex_t m_mutex;
		std::string m_hostName;
		std::string m_databaseName;
		std::string m_userName;
		std::string m_password;
		MYSQL m_database;
		bool m_isOpen;

		void open(void);
		void close(void);

	private:
		MySQLBase(const MySQLBase &other);
		MySQLBase &operator=(const MySQLBase &other);

};

#endif // _MYSQLBASE_H_
